package main

import (
	"Godzilla/common/etcd"
	"Godzilla/conf/databases"
	"Godzilla/enum/fileds"
	"Godzilla/models"
	"Godzilla/tcp/proto"
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
	"io"
	"log"
	"net"
	"strconv"
	"sync"
	"time"
)

//分布式tcp中央

type Node struct {
	//客户端地址
	Address    	string
	//客户端连接
	Conn 		net.Conn
	//数据
	DataQueue	chan []byte
}

var (
	ClientMap map[string]*Node = make(map[string]*Node, 0)
	RWLocker sync.RWMutex

	clientEtcd *clientv3.Client
)

func main()  {
	var (
		Host    string
		Port    string
		address string
	)

	//读取etcd配置
	databases.EtcdSetConfig()

	//读取tcpServer配置
	databases.TcpSetConfig()
	Host = databases.GetTcpConfig("Host")
	Port = databases.GetTcpConfig("Port")
	log.Println("Host:", Host)
	log.Println("Port:", Port)

	//开放端口
	hawkServer, err := net.ResolveTCPAddr("tcp", Host+":"+Port)
	if err != nil {
		log.Println("初始化服务端tcp套接字报错:", err.Error())
	}

	listen, err := net.ListenTCP("tcp", hawkServer)
	//listen, err := net.Listen("tcp", Host+":"+Port)
	if err != nil {
		log.Println("tcp监听端口报错:",err.Error())
		return
	}
	defer listen.Close()

	clientEtcd, err = etcd.NewEtcdCli()
	if err != nil {
		log.Println(err.Error())
	}
	defer clientEtcd.Close()

	for  {
		conn, err := listen.Accept() //接受连接
		if err != nil {
			log.Println("接受连接报错:",err.Error())
			continue
		}

		address = conn.RemoteAddr().String()
		node := &Node{
			Address:   address,
			Conn:      conn,
			DataQueue: make(chan []byte, 50),
		}

		RWLocker.Lock()
		//判断数据目标对象在哪个服务端，然后拿取句柄发送到目标客户端
		ClientMap[conn.RemoteAddr().String()] = node
		RWLocker.Unlock()

		go process(conn)

	}
}

func process(conn net.Conn)  {
	defer conn.Close()//关闭连接
	reader := bufio.NewReader(conn)
	for  {
		msg, err := proto.Decode(reader)

		fmt.Println("收到消息：", msg)
		if err == io.EOF {
			return
		}
		if err != nil {
			fmt.Println("decode失败，err:", err)
			return
		}

		message := models.Message{}
		err = json.Unmarshal([]byte(msg), &message)
		if err != nil {
			log.Println("数据Unmarshal错误:", err.Error())
		}

		if message.Cmd == fileds.CMD_HEART {
			log.Println("这是心跳消息，不处理")
			//不往下执行
			continue
		}

		//拿出目标dstid 在客户端已经解析为用户id
		dstId := message.DstId
		if dstId == 0 {
			log.Println("错误:dstId为0")
		}

		ctx, _ := context.WithTimeout(context.Background(), 5 * time.Second)

		if message.Cmd == fileds.CMD_ROOM_MSG {
			//群聊模式
			resultPrefix, err := clientEtcd.Get(ctx, "/group/group-" + strconv.Itoa(int(message.DstId)) + "-", clientv3.WithPrefix())
			if err != nil {
				log.Println("etcd前缀查找:", err.Error())
				return
			}
			if len(resultPrefix.Kvs) == 0 {
				log.Println("etcd prefix查找为空")
				return
			}
			set := make(map[string]bool)
			for _, v := range resultPrefix.Kvs {
				set[string(v.Value)] = true
			}
			for cli, _ := range set{

				//排除发送端
				if cli != conn.RemoteAddr().String() {
					b, err := proto.Encode(string(msg))
					if err != nil {
						fmt.Println("Encode失败，err:", err)
						return
					}
					//给用户所在客户单发送消息
					ClientMap[cli].Conn.Write(b)
				}
			}


		} else if message.Cmd == fileds.CMD_SINGLE_MSG {
			//单聊模式
			//通过etcd查找用户所在的客户单
			result, err := clientEtcd.Get(ctx, "/inline/" + strconv.Itoa(int(dstId)))
			if err != nil {
				log.Println("etcd获取用户所在客户端失败:", err.Error())
			}
			if len(result.Kvs) == 0 {
				log.Println("etcd 未找到用户:", dstId)
				return
			}
			targetAddress := result.Kvs[0].Value
			log.Println("目标用户所在客户端:", targetAddress)


			//TODO 将msg解析然后将消息发送到特定的客户端
			b, err := proto.Encode(string(msg))
			if err != nil {
				fmt.Println("Encode失败，err:", err)
				return
			}
			//给用户所在客户单发送消息
			ClientMap[string(targetAddress)].Conn.Write(b)
		}

		//conn.Write(b)

	}
}
